package
{
	import flash.display.Sprite;

	[SWF(backgroundColor=0xffffff, width=465, height=465, frameRate=60)]
	public class math_pow_test extends Sprite
	{

		public function math_pow_test()
		{
			var tester:Tester = new Tester("0乗から10乗までの累乗の計算について比較します。(500000回ループ)", this);
			var count:uint = 50000;

			//テストの登録
			tester.register(test, "empty", [count, 0]);
			for (var i:int = 0; i <= 10; i++)
			{
				tester.register(test1, "Math.pow(n, m)", [count, i]);
			}
			for (i = 0; i <= 10; i++)
			{
				tester.register(test2, "if/else", [count, i]);
			}
			for (i = 0; i <= 10; i++)
			{
				tester.register(test3, "switch/case", [count, i]);
			}
			for (i = 0; i <= 10; i++)
			{
				tester.register(test4, "三項演算子", [count, i]);
			}
			for (i = 0; i <= 10; i++)
			{
				tester.register(test5, "ループ", [count, i]);
			}
		}

		//処理のオーバーヘッドを求めるための空処理
		public function test(count:uint, range:uint):void
		{
			for (var i:int = 0; i < count; i++)
			{
				var e:uint = Math.round(Math.random() * range);
				var v:Number = Math.random();
			}
		}

		//Math.powで計算
		public function test1(count:uint, range:uint):void
		{
			var r:Number;

			for (var i:int = 0; i < count; i++)
			{
				var e:uint = Math.round(Math.random() * range);
				var v:Number = Math.random();
				r = Math.pow(v, e);
			}
		}

		//指数別にifで計算
		public function test2(count:uint, range:uint):void
		{
			var r:Number;

			for (var i:int = 0; i < count; i++)
			{
				var e:uint = Math.round(Math.random() * range);
				var v:Number = Math.random();
				if (e === 0)
				{
					r = 1;
				}
				else if (e === 1)
				{
					r = v;
				}
				else if (e === 2)
				{
					r = v * v;
				}
				else if (e === 3)
				{
					r = v * v * v;
				}
				else if (e === 4)
				{
					r = v * v * v * v;
				}
				else if (e === 5)
				{
					r = v * v * v * v * v;
				}
				else if (e === 6)
				{
					r = v * v * v * v * v * v;
				}
				else if (e === 7)
				{
					r = v * v * v * v * v * v * v;
				}
				else if (e === 8)
				{
					r = v * v * v * v * v * v * v * v;
				}
				else if (e === 9)
				{
					r = v * v * v * v * v * v * v * v * v;
				}
				else if (e === 10)
				{
					r = v * v * v * v * v * v * v * v * v * v;
				}
			}
		}

		//指数別にswitchで計算
		public function test3(count:uint, range:uint):void
		{
			var r:Number;

			for (var i:int = 0; i < count; i++)
			{
				var e:uint = Math.round(Math.random() * range);
				var v:Number = Math.random();
				switch (e)
				{
					case 0:
						r = 1;
						break;
					case 1:
						r = v;
						break;
					case 2:
						r = v * v;
						break;
					case 3:
						r = v * v * v;
						break;
					case 4:
						r = v * v * v * v;
						break;
					case 5:
						r = v * v * v * v * v;
						break;
					case 6:
						r = v * v * v * v * v * v;
						break;
					case 7:
						r = v * v * v * v * v * v * v;
						break;
					case 8:
						r = v * v * v * v * v * v * v * v;
						break;
					case 9:
						r = v * v * v * v * v * v * v * v * v;
						break;
					default:
						r = v * v * v * v * v * v * v * v * v * v;
						break;
				}
			}
		}

		//三項演算子で計算
		public function test4(count:uint, range:uint):void
		{
			var r:Number;

			for (var i:int = 0; i < count; i++)
			{
				var e:uint = Math.round(Math.random() * range);
				var v:Number = Math.random();
				r = e === 0 ? 1 : e === 1 ? v : e === 2 ? v * v : e === 3 ? v * v * v : e === 4 ? v * v * v * v : e === 5 ? v * v * v * v * v : e === 6 ? v * v * v * v * v * v : e === 7 ? v * v * v * v * v * v * v : e === 8 ? v * v * v * v * v * v * v * v : e === 9 ? v * v * v * v * v * v * v * v : v * v * v * v * v * v * v * v * v;
			}
		}

		//ループで計算
		public function test5(count:uint, range:uint):void
		{
			var r:Number;

			for (var i:int = 0; i < count; i++)
			{
				var e:uint = Math.round(Math.random() * range);
				var v:Number = Math.random();
				if (e === 0)
				{
					r = 1;
				}
				else
				{
					r = v;
					for (var j:int = 0; j < e - 1; j++)
					{
						r = r * v;
					}
				}
			}
		}
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////
//以下テストツール
//////////////////////////////////////////////////////////////////////////////////////////////
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.utils.getTimer;

class Tester extends Sprite
{

	private var _console:TextField;

	private var _tests:Array = [];

	public function Tester(caption:String, parent:Sprite)
	{
		parent.addChild(this);

		var label:TextField = new TextField();
		with (label)
		{
			defaultTextFormat = new TextFormat(null, 14);
			text = "Start";
			border = true;
			mouseEnabled = false;
			height = textHeight + 6;
			width = textWidth + 16;
		}

		with (addChild(new Sprite))
		{
			addChild(label);
			buttonMode = true;
			useHandCursor = true;
			addEventListener(MouseEvent.CLICK, start);
		}

		with (addChild(_console = new TextField))
		{
			defaultTextFormat = new TextFormat(null, 14);
			multiline = true;
			type = TextFieldType.INPUT;
			width = 460;
			height = 430;
			y = 30;
			border = true;
		}

		_console.text = caption;
	}

	public function register(test:Function, title:String, args:Array = null):void
	{
		_tests[_tests.length] = {test: test, title: title, args: args};
	}

	private function callLater(fn:Function, args:Array = null):void
	{
		addEventListener(Event.ENTER_FRAME, function(e:Event):void
		{
			removeEventListener(Event.ENTER_FRAME, arguments.callee);
			addEventListener(Event.ENTER_FRAME, function(e:Event):void
			{
				removeEventListener(Event.ENTER_FRAME, arguments.callee);
				fn.apply(null, args);
			});
		});
	}

	private function doTest(tests:Array):void
	{

		var test:Object = tests.shift();
		if (test === null)
		{
			mouseEnabled = true;
			mouseChildren = true;
			alpha = 1;
			return;
		}

		_console.appendText("[" + test.title + "]を引数[" + test.args + "]で実行...");
		_console.scrollV = _console.maxScrollV;

		callLater(function():void
		{
			var t:uint = getTimer();
			test.test.apply(null, test.args);
			t = getTimer() - t;

			callLater(function():void
			{
				_console.appendText(" " + t + "ms\n");
				_console.scrollV = _console.maxScrollV;
				callLater(doTest, [tests]);
			});
		});
	}

	private function start(e:MouseEvent):void
	{
		_console.text = "";
		mouseEnabled = false;
		mouseChildren = false;
		alpha = 0.6;
		doTest(_tests.concat());
	}
}
